﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Evaluant.NLinq.Expressions
{
    public class AnonymousParameterList : Expression, IList<AnonymousParameter>
    {
        public AnonymousParameterList(AnonymousParameter parameter)
        {
            parameters = new List<AnonymousParameter>();
            parameters.Add(parameter);
        }

        public AnonymousParameterList(IEnumerable<AnonymousParameter> parameters)
        {
            this.parameters = new List<AnonymousParameter>(parameters);
        }

        public AnonymousParameterList()
        {
            parameters = new List<AnonymousParameter>();
        }

        IList<AnonymousParameter> parameters;


        public override void Accept(NLinqVisitor visitor)
        {
            foreach (AnonymousParameter param in this)
            {
                param.Accept(visitor);
            }
        }

        public override ExpressionTypes ExpressionType
        {
            get { return ExpressionTypes.AnonymousParameters; }
        }

        #region IList<AnonymousParameter> Members

        public int IndexOf(AnonymousParameter item)
        {
            return parameters.IndexOf(item);
        }

        public void Insert(int index, AnonymousParameter item)
        {
            parameters.Insert(index, item);
        }

        public void RemoveAt(int index)
        {
            parameters.RemoveAt(index);
        }

        public AnonymousParameter this[int index]
        {
            get
            {
                return parameters[index];
            }
            set
            {
                parameters[index] = value;
            }
        }

        #endregion

        #region ICollection<AnonymousParameter> Members

        public void Add(AnonymousParameter item)
        {
            parameters.Add(item);
        }

        public void Clear()
        {
            parameters.Clear();
        }

        public bool Contains(AnonymousParameter item)
        {
            return parameters.Contains(item);
        }

        public void CopyTo(AnonymousParameter[] array, int arrayIndex)
        {
            parameters.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return parameters.Count; }
        }

        public bool IsReadOnly
        {
            get { return parameters.IsReadOnly; }
        }

        public bool Remove(AnonymousParameter item)
        {
            return parameters.Remove(item);
        }

        #endregion

        #region IEnumerable<AnonymousParameter> Members

        public IEnumerator<AnonymousParameter> GetEnumerator()
        {
            return parameters.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return parameters.GetEnumerator();
        }

        #endregion

        public AnonymousParameter[] ToArray()
        {
            return ((List<AnonymousParameter>)parameters).ToArray();
        }
    }

    public class AnonymousParameter : Expression
    {
        public AnonymousParameter(string identifier, Expression expression)
            : this(new Identifier(identifier), expression)
        {
        }
        public AnonymousParameter(Identifier identifier, Expression expression)
        {
            if (identifier.Text != null)
                this.identifier = identifier;
            this.expression = expression;
        }

        private Identifier identifier;

        public Identifier Identifier
        {
            get { return identifier; }
            set { identifier = value; }
        }

        private Expression expression;

        public Expression Expression
        {
            get { return expression; }
            set { expression = value; }
        }

        public string GetPropertyName()
        {
            if (identifier != null)
                return identifier.Text;

            MemberExpression s = Expression as MemberExpression;
            if (s == null)
            {
                throw new NLinqException("In anonymous types, a property name mus be set");
            }

            Identifier i = s.Statement as Identifier;
            if (i == null)
            {
                throw new NLinqException("In anonymous types, a property name mus be set");
            }

            return i.Text;
        }

        public override void Accept(NLinqVisitor visitor)
        {
            throw new NotImplementedException();
        }

        public override ExpressionTypes ExpressionType
        {
            get { return ExpressionTypes.Parameter; }
        }
    }

}
